﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
using System.Windows;
using System.Windows.Controls;
using DeepEarth.Client.MapControl;
using DeepEarth.Client.Services.NearMap;

namespace DeepEarth.Client.Controls.DEMap.DateLineLite
{
    [TemplatePart(Name = PART_DatesList, Type = typeof(ComboBox))]
    public class DatePicker : Control, IMapControl<Map>
    {
        private const string PART_DatesList = "PART_DatesList";

        private ComboBox _datesList;

        private Map _mapInstance;
        private string _mapName;

        private DateTime? _currentDate;

        private bool _isProcessChanged = true;

        public DatePicker()
        {
            DefaultStyleKey = typeof(DatePicker);

            if (!DesignerProperties.IsInDesignTool)
            {
                Loaded += DateLine_Loaded;
            }
        }

        void DateLine_Loaded(object sender, RoutedEventArgs e)
        {
            SetMapInstance(MapName);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _datesList = (ComboBox)GetTemplateChild(PART_DatesList);

            if (!DesignerProperties.IsInDesignTool)
            {
                if (_datesList != null)
                {
                    _datesList.SelectionChanged += DatesListSelectionChanged;

                    FillDatesList();
                    if (_datesList.Items.Count > 0)
                    {
                        _datesList.SelectedIndex = 0;
                    }
                }
            }
        }

        private void FillDatesList()
        {
            //deleting old script and generating new
            var center = MapInstance.GeoCenter;

            if (!double.IsNaN(center.Longitude) && !double.IsNaN(center.Latitude))
            {
                var centerInPixels = _mapInstance.CoordHelper.GeoToPixelAtZoom(center, Convert.ToInt32(_mapInstance.ZoomLevel));
                var wc = new WebClient();
                wc.DownloadStringCompleted += (o, e) => ParseDates(e.Result);

                var x = Convert.ToInt64(centerInPixels.X / 256);
                var y = Convert.ToInt64(centerInPixels.Y / 256);
                var z = Math.Round(_mapInstance.ZoomLevel);
                var url = string.Format("/NearMapsJsonHandler.ashx?x={0}&y={1}&z={2}", x, y, z);

                wc.DownloadStringAsync(new Uri(url, UriKind.Relative));
            }
        }

        private void DatesListSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (_isProcessChanged)
            {
                if (_datesList.SelectedItem == null)
                {
                    SetNewNearMapSource(null);
                }
                else
                {
                    SetNewNearMapSource((DateTime)_datesList.SelectedItem);
                }
            }
        }

        private NearMapTileSource NewNearMapTileSource()
        {
            return new NearMapTileSource(NearMapModes.NearMap) { DateMap = CurrentShortDate() };
        }

        [DataContract]
        public class NearMapLayers
        {
            [DataMember(Name = "layers")]
            public NearMapVert Layers { get; set; }
        }

        [DataContract]
        public class NearMapVert
        {
            [DataMember(Name = "Vert")]
            public List<DateTime> Vert { get; set; }
        }

        public void ParseDates(string data)
        {
            var jsonObject = data.JsonToObject<NearMapLayers>();
            if(jsonObject.Layers != null)
            {
                var result = jsonObject.Layers.Vert;

                var basicDate = new DateTime(1970, 1, 1);

                result.Reverse();

                //finding nearest date if current date is absent in dates list, then use it
                if (this._datesList.SelectedItem != null)
                {
                    var date = (DateTime)this._datesList.SelectedItem;
                    if (!result.Contains(date))
                    {

                        if ((this._currentDate != null) && (result.Count > 0))
                        {
                            var minDate = result[0];

                            var cmp = Math.Abs(minDate.CompareTo(date));

                            foreach (var d in result.Where(d => cmp > Math.Abs(d.CompareTo(date))))
                            {
                                minDate = d;
                            }

                            this.SetNewNearMapSource(minDate);
                        }
                        result.Insert(0, date);
                    }

                    this._isProcessChanged = false;
                    this._datesList.ItemsSource = result;
                    this._datesList.SelectedItem = date;
                    this._isProcessChanged = true;
                }
                else
                {
                    this._datesList.ItemsSource = result;
                    if (result.Count > 0)
                    {
                        this._datesList.SelectedIndex = 0;
                    }
                }
            }
        }

        private void SetNewNearMapSource(DateTime? date)
        {
            if ((_mapInstance != null) && (_currentDate != date))
            {
                var source = _mapInstance.BaseLayer.Source as NearMapTileSource;

                if (source != null)
                {
                    _mapInstance.BaseLayer.Source = NewNearMapTileSource();
                }

                _currentDate = date;
            }
        }

        private void Events_MapViewChangedEnded(object sender, MapControl.Events.MapEventArgs args)
        {
            //recreating dates list
            FillDatesList();
        }

        private string CurrentShortDate()
        {
            if ((_mapInstance != null) && (_datesList.SelectedItem != null))
            {
                return ((DateTime)_datesList.SelectedItem).ToString("yyyyMMdd");
            }
            return null;
        }

        #region IMapControl<Map> Members

        public string MapName
        {
            get { return _mapName; }
            set
            {
                _mapName = value;
                SetMapInstance(MapName);
            }
        }

        public Map MapInstance
        {
            get { return _mapInstance; }
            set
            {
                if (_mapInstance != null)
                {
                    _mapInstance.Events.MapViewChangedEnded -= Events_MapViewChangedEnded;
                }

                _mapInstance = value;

                if (_mapInstance != null)
                {
                    _mapInstance.Events.MapViewChangedEnded += Events_MapViewChangedEnded;
                }
            }
        }

        public void Dispose()
        {
            MapInstance = null;
        }


        private void SetMapInstance(string mapname)
        {
            MapInstance = Utilities.FindVisualChildByName<Map>(Application.Current.RootVisual, mapname);
        }

        #endregion

    }
}